#include <stdlib.h>

#include "map_utils.h"

//------------------------------------------------------------------------------

int _FindByAddr(func_map *pmap, addr_t proc_addr) {

    CHECK_DBG_ERR(pmap, NULL_PTR);
    if(pmap->size_ == 0)
        return -1;
    CHECK_DBG_ERR(pmap->map_, NULL_PTR);
     
    unsigned int i = 0;
    for(i = 0; i < pmap->size_; i++)
        if(pmap->map_[i].addr_ > proc_addr)
            return i - 1;
    return -1;
}

//------------------------------------------------------------------------------

static int FuncMapCmp(const void *p1, const void *p2) {
    return ((func_map_info*) p1)->addr_ - ((func_map_info*) p2)->addr_;
}


//------------------------------------------------------------------------------

void SortFuncMap(func_map *pmap) {
    CHECK_DBG_ERR(pmap, NULL_PTR);
    if(pmap->size_ == 0)
        return;
    CHECK_DBG_ERR(pmap->map_, NULL_PTR);

    qsort(pmap->map_, pmap->size_, sizeof(func_map_info), FuncMapCmp);
}

//------------------------------------------------------------------------------

TBGError MergeFuncMaps(func_map *fm1, func_map *fm2, func_map *fm_res) {
    TBGError ret = 0;
    CHECK_DBG_ERR(fm1, NULL_PTR);
    CHECK_DBG_ERR(fm2, NULL_PTR);
    
    if(fm1->size_) {
        CHECK_DBG_ERR(fm1->map_, NULL_PTR);
        CHECK_DBG_ERR(fm1->names_, NULL_PTR);
    }
    if(fm2->size_) {
        CHECK_DBG_ERR(fm2->map_, NULL_PTR);
        CHECK_DBG_ERR(fm2->names_, NULL_PTR);
    }

    fm_res->size_ = fm1->size_ + fm2->size_;
    if(fm_res->size_ == 0)
        goto exit_point; // nothing to do:)

    fm_res->map_ = (func_map_info*) malloc(fm_res->size_ *
                                           sizeof(func_map_info));
    fm_res->names_ = (name_t*) malloc(fm_res->size_ * sizeof(name_t));
    CHECK_RET(fm_res->map_, CANNOT_ALLOC_MEMORY, free_point, ret);
    CHECK_RET(fm_res->names_, CANNOT_ALLOC_MEMORY, free_point, ret);

    int i = 0, j = 0;
    for(i = 0; i < fm1->size_; ++i) {
        fm_res->map_[i].addr_ = fm1->map_[i].addr_;
        fm_res->map_[i].name_idx_ = fm1->map_[i].name_idx_;
        int k = 0;
        for(k = 0; k < func_name_length_; ++k)
            fm_res->names_[i][k] = fm1->names_[i][k];
    }
    for(j = 0; j < fm2->size_; ++i, ++j) {
        fm_res->map_[i].addr_ = fm2->map_[j].addr_;
        fm_res->map_[i].name_idx_ = fm2->map_[j].name_idx_ + fm1->size_;
        int k = 0;
        for(k = 0; k < func_name_length_; ++k)
            fm_res->names_[i][k] = fm2->names_[j][k];
    }

free_point:
    if(ret) {
        free(fm_res->names_);
        free(fm_res->map_);
    }
exit_point:
    return ret;
}

//------------------------------------------------------------------------------

TBGError JoinToFuncMap(func_map *base_fm, func_map *join_fm) {
    TBGError ret = 0;
    CHECK_DBG_ERR(base_fm, NULL_PTR);
    CHECK_DBG_ERR(join_fm, NULL_PTR);

    func_map temp_fm = {};
    CHECK_CALL(MergeFuncMaps(base_fm, join_fm, &temp_fm), exit_point, ret);
    free(base_fm->names_);
    free(base_fm->map_);
    base_fm->names_ = temp_fm.names_;
    base_fm->map_   = temp_fm.map_;
    base_fm->size_  = temp_fm.size_;
    
exit_point:
    return ret;
}
